﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using ACL.Supervisor;

namespace ACL.Comm
{   
    [ServiceBehavior(InstanceContextMode= InstanceContextMode.PerCall)]


    public  class AgentService : IAgentPool
    {



        private static List<Tuple<Agent, IAgentContractCallBack>> Agents = new List<Tuple<Agent, IAgentContractCallBack>>();

        private List<Message> Messages = new List<Message>();

        static AgentHelp agentHelp = new AgentHelp();


        #region
        //get help for specific agent than for all
        public bool CanIGetSomeHelp(AgentTracker agentTracker)
        {
            Shout(new Message { sender = agentTracker.agent, recipeint = agentTracker.agent, body = string.Format("agent {0} needs help ", agentTracker.agent.Name), subject = "Help!!" });
            string id = agentTracker.agent.Id;
            if (GetAgents().Count > 1)
            {
                GetAgentCallBackListByID(agentHelp.GetHelp(agentTracker, GetAgents().Where(b => b.Id != id).ToList()).Id).DownloadFile(agentTracker.args[0], agentTracker.args[1], agentTracker.args[2], 5);
            }
            return null != agentHelp.GetHelp(agentTracker, GetAgents().Where(b => b.Id != id).ToList());
       }


        //check if agent can help others
        public AgentTracker CanIHelp(Agent agent)
        {

          return  agentHelp.FindAgentInNeed(agent);
           
        }

        //message
        public void Whisper(Message message)
        {

            AddMessage(message);
       

          
          GetAgentCallBackListByID(message.recipeint.Id).CallBackFUnction(string.Format("agent {0}  message {1}", message.sender.Name, message.body));
            
        }

        public void AddMessage(Message message)
        {
               Messages.Add(message);

             using (var context = new ACL.DB.aclp2pEntities())
            {

                ACL.DB.message m = new ACL.DB.message();
                m.messageText = message.body;
                m.MessageTo = new Guid(message.recipeint.Id);
                m.MessageFrom = new Guid(message.sender.Id);
                m.idMessage = Guid.NewGuid();
                m.MessageTime = DateTime.Now;

                context.AddTomessages(m);
                context.SaveChanges();
            }


        }

        public void AddAgent(Agent agent)
        {   
            using (var context = new ACL.DB.aclp2pEntities())
            {

                ACL.DB.agent a = new ACL.DB.agent();
                a.idAgent = new Guid(agent.Id);
                a.AgentName = agent.Name;
                a.AgentSkills = string.Join(",", agent.Skills);
                a.AgentTime = DateTime.Now;


                context.AddToagents(a);
                context.SaveChanges();
            }


            Agents.Add(new Tuple<Agent, IAgentContractCallBack>(agent, OperationContext.Current.GetCallbackChannel<IAgentContractCallBack>()));
            Shout(new Message { sender = agent, recipeint = agent, body = string.Format("agent {0} has connected ", agent.Name), subject = "hi" });


  


        }

      

        public void Shout(Message message)
        {
            AddMessage(message);

            foreach (var callback in GetAgentCallBackList())
            {

                callback.CallBackFUnction(string.Format("agent {0} Message", message.recipeint.Name, message.body));
            }
            
        }


        public List<Message> GetUnReadMessages(Agent agent)
        {
            return Messages.Where(b => b.sender.Id == agent.Id).ToList();

        }

        public List<Message> GetAllReadMessages(Agent agent)
        {
            return Messages.Where(b => b.sender.Id == agent.Id).ToList();

        }

        public List<Message> GetAllMessages(Agent agent)
        {
            return Messages.Where(b => b.sender.Id == agent.Id).ToList();

        }
        #endregion

        #region
        //connection

        public List<Agent> GetAgents()
        {
            return Agents.Select(p=> p.Item1).ToList();
        }

        public List<IAgentContractCallBack> GetAgentCallBackList()
        {
            return Agents.Select(p => p.Item2).ToList();
        }

        public IAgentContractCallBack GetAgentCallBackListByID(string id)
        {
            return Agents.Where(b => b.Item1.Id == id).Select(p => p.Item2).FirstOrDefault();
        }

        public void NormalFunction()
        {
            

        }


        


        /// <summary>
        /// NewId is assigned to ensure uniqueness
        /// </summary>
        /// <param name="agent"></param>
        /// <returns></returns>
        public void Subscribe(Agent agent)
        {
           

            if (!GetAgents().Contains(agent))
            {
                //get the contract
                AddAgent(agent);

                foreach (var callback in GetAgentCallBackList())
                {
                    callback.UpdateAgentListAdd(agent);
                    callback.CallBackFUnction(string.Format("agent {0} has joined", agent.Name)); }
                    
                }            
            }
            

           

        

        public void UnSubscribe(Agent agent)
        {          

            if (GetAgents().Where(b => b.Id == agent.Id).Count()>0)
            {
                Agents.Remove(Agents.Find(a => a.Item1.Id == agent.Id));
                
                Shout(new Message { sender = agent, recipeint = agent, body = string.Format("agent {0} has disconnected ", agent.Id), subject = "hi" });
            
                     foreach (var callback in GetAgentCallBackList())
                {
                    callback.UpdateAgentListRemove(agent);
                 
                    
                }    
            }      
     


          
        }

        public void TearDownService()
        {
            Agents.Clear();

        }

        #endregion

        public static bool taskComplete;

        public bool TaskComplete()
        {
            return taskComplete;
        }
    }
}
